package org.makcro.sms.services.chat.web.server.services;

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.dozer.Mapper;
import org.makcro.sms.services.chat.base.dto.HistoryItem;
import org.makcro.sms.services.chat.model.Agent;
import org.makcro.sms.services.chat.model.Question;
import org.makcro.sms.services.chat.web.client.Constants;
import org.makcro.sms.services.chat.web.client.services.message.MessageService;
import org.makcro.sms.services.chat.web.shared.dto.HistoryItemDto;
import org.makcro.sms.services.chat.web.shared.dto.QuestionDto;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.extjs.gxt.ui.client.data.BasePagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;

public class MessageServiceFacadeImpl implements MessageService {

	/**
	 * Logger instance
	 */
	private Logger														logger	= Logger.getLogger( MessageServiceFacadeImpl.class );

	/**
	 * Message service used to actually send messages
	 */
	private org.makcro.sms.services.chat.base.business.MessageService	messageService;

	private Mapper														mapper;

	/**
	 * Finds new messages that are not assigned to any agent
	 */
	@Override
	public List<QuestionDto> getNewMessages() {
		List<Question> unAssignedQuestions = messageService.findNewMessages();

		List<QuestionDto> dtoList = new ArrayList<QuestionDto>();

		for (Question question : unAssignedQuestions) {
			QuestionDto questionDto = mapper.map( question, QuestionDto.class );
			dtoList.add( questionDto );
		}
		return dtoList;
	}

	@Override
	public List<HistoryItemDto> getUserHistory(String phoneNumber) {
		List<HistoryItemDto> historyItemDtos = new ArrayList<HistoryItemDto>();
		try {
			List<HistoryItem> history = messageService.findHistory( phoneNumber );
			for (HistoryItem historyItem : history) {
				HistoryItemDto historyItemDto = mapper.map( historyItem, HistoryItemDto.class );
				historyItemDtos.add( historyItemDto );
			}

			return historyItemDtos;
		}
		catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Performs question reservation for the current agent.
	 * 
	 * @param questionId
	 *            id of the question to be reserved
	 * @return true if reservation was successful, otherwise false
	 */
	@Override
	public Boolean checkAndReserveQuestion(Integer questionId) {

		Agent currentAgent = getCurrentAgent();
		// try to reserve question
		Boolean reservationResult = messageService.checkAndReserveQuestion( questionId, currentAgent );
		logger.debug( MessageFormat.format( "Assigned message with id [{0}] and to agent [{1}]", questionId, currentAgent.getAgentUserName() ) );

		return reservationResult;
	}

	@Override
	public void cancelQuestionReservation(Integer questionId) {
		Agent currentAgent = getCurrentAgent();
		messageService.cancelQuestionReservation( questionId, currentAgent );

		logger.debug( MessageFormat.format( "Canceled reservation of message [{0}] for agent [{1}]", questionId, currentAgent.getAgentUserName() ) );
	}

	@Override
	public Long sendMessage(Long referenceId, String messageText) {
		Long sendingResult = messageService.sendMessage( referenceId, messageText );
		logger.debug( MessageFormat.format( "Response with reference id [{0}] sent, assigned core id is [{1}]", referenceId, sendingResult ) );

		return sendingResult;
	}

	@Override
	public List<HistoryItemDto> getCurrentAgentsMessages() {
		Agent currentAgent = getCurrentAgent();

		List<HistoryItem> messages = messageService.findByAgent( currentAgent );
		List<HistoryItemDto> dtoMessages = new ArrayList<HistoryItemDto>( messages.size() );

		for (HistoryItem historyItem : messages) {

			HistoryItemDto historyItemDto = mapper.map( historyItem, HistoryItemDto.class );
			dtoMessages.add( historyItemDto );
		}

		return dtoMessages;
	}

	@Override
	public PagingLoadResult<HistoryItemDto> getCurrentAgentsMessages(PagingLoadConfig loadConfig) {
		Agent currentAgent = getCurrentAgent();
		// extract paging params
		int offset = loadConfig.getOffset();
		int limit = loadConfig.getLimit();

		// load paging data
		List<HistoryItem> agentsMessages = messageService.findByAgent( currentAgent, new int[] { offset, limit } );
		int countByAgent = messageService.findCountByAgent( currentAgent );

		// convert to dto
		List<HistoryItemDto> dtoMessages = new ArrayList<HistoryItemDto>( agentsMessages.size() );
		for (HistoryItem historyItem : agentsMessages) {
			HistoryItemDto historyItemDto = mapper.map( historyItem, HistoryItemDto.class );
			dtoMessages.add( historyItemDto );
		}

		PagingLoadResult<HistoryItemDto> result = new BasePagingLoadResult<HistoryItemDto>( dtoMessages, offset, countByAgent );
		return result;
	}

	/**
	 * Get's the currently logged in agent
	 * 
	 * @return instance of {@link Agent}
	 */
	private Agent getCurrentAgent() {
		ServletRequestAttributes currentRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
		HttpSession session = currentRequestAttributes.getRequest().getSession( true );

		Agent agent = (Agent) session.getAttribute( Constants.Session.CURRENT_USER );
		return agent;
	}

	@Override
	public List<HistoryItemDto> getAllHistory() {
		List<HistoryItem> allHistory = messageService.getAllHistory();
		List<HistoryItemDto> allHistoryDto = new ArrayList<HistoryItemDto>( allHistory.size() );

		for (HistoryItem historyItem : allHistory) {
			HistoryItemDto historyItemDto = mapper.map( historyItem, HistoryItemDto.class );
			allHistoryDto.add( historyItemDto );
		}

		return allHistoryDto;
	}

	@Override
	public PagingLoadResult<HistoryItemDto> getAllHistory(PagingLoadConfig loadConfig) {
		int offset = loadConfig.getOffset();
		int limit = loadConfig.getLimit();
		// load all history count
		int allHistoryCount = this.messageService.getAllHistoryCount();
		List<HistoryItem> history = this.messageService.getAllHistory( new int[] { offset, limit } );
		// transform results to dto
		List<HistoryItemDto> historyDto = new ArrayList<HistoryItemDto>( history.size() );
		
		for (HistoryItem historyItem : history) {
			HistoryItemDto itemDto = mapper.map( historyItem, HistoryItemDto.class );
			historyDto.add( itemDto );
		}
		
		PagingLoadResult<HistoryItemDto> pagingLoadResult = new BasePagingLoadResult<HistoryItemDto>( historyDto, offset, allHistoryCount );
		
		return pagingLoadResult;
	}

	public void setMessageService(org.makcro.sms.services.chat.base.business.MessageService messageService) {
		this.messageService = messageService;
	}

	public void setMapper(Mapper mapper) {
		this.mapper = mapper;
	}

}
